#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>

// 平台相关定义, 让share部分的代码在不同平台上都能编译通过
#ifdef PLATFORM_582
#include "CH58x_common.h"
#else
#define __HIGH_CODE
#endif // !MCU582

// 版本相关定义: ----------------------------------------------------------------------------------------
// 修改具体版本定义在m0:zqm_app.c/cat1:zq_app.c末尾修改ZQM_AUTO_VERSION
#define ZQ_VER_MAX_LEN					9		// the max version buffer size, include \0。like 1.2.3.45
#define ZQ_VER_STR_MAX_LEN				24		// the max version string buffer size, include \0。like GD6S_V1.2.3.45
#define ZQ_AUTO_VER_HEAD_LEN			12		// 参照ZQM_AUTO_VERSION定义的描述
#define ZQ_AUTO_VER_BLE_LEN				12		// 参照ZQM_AUTO_VERSION定义的描述
#define ZQ_AUTO_VER_PREFIX_LEN			6		// 参照ZQM_AUTO_VERSION定义的描述，以及ZQ_VER_PREFIX

extern const char *ZQ_AUTO_SW_VER; 			// 自动软件版本号，类似"***AUTO_VER_M0:3001001036++AAKM_V1.0.2.00"
extern const char *ZQ_AUTO_HW_VER; 			// 硬件版本号，类似"AAKM_V1.0.2.00"
// 软件版本号定义
#define ZQ_SW_VER_STR	(ZQ_AUTO_SW_VER + ZQ_AUTO_VER_HEAD_LEN + ZQ_AUTO_VER_BLE_LEN) 	// 带前缀软件版本号，类似"ABCM_V1.0.2.00"
#define ZQ_SW_VER		(ZQ_SW_VER_STR + ZQ_AUTO_VER_PREFIX_LEN)  						// 软件版本号，类似"1.0.2.00"
#define ZQ_M0_SW_VER	ZQ_SW_VER  														// obsoleted macro for ftm module
#define ZQ_CAT1_SW_VER	ZQ_SW_VER  														// obsoleted macro for ftm module
// 硬件版本号定义
#define ZQ_HW_VER_STR	(ZQ_AUTO_HW_VER)												// 带前缀硬件版本号，类似"ABCM_V1.0.2.00"
#define ZQ_HW_VER		(ZQ_AUTO_HW_VER + ZQ_AUTO_VER_PREFIX_LEN)  						// 软件版本号，类似"1.0.2.00"
#define ZQ_M0_HW_VER	ZQ_HW_VER  														// obsoleted macro for ftm module
#define ZQ_CAT1_HW_VER	ZQ_HW_VER  														// obsoleted macro for ftm module

// CPU之间通讯版本定义, 修改通讯协议不兼容旧版本时候，升级此版本号 
#define COMM_PROTOCOL_VER 			(3)            // 1-199, 0表示无效

// 1. M0和CAT1通讯相关 ---------------------------------------------------------------------------------
// cmd00: 保留，
// cmd01-17(16进制): cmd01, cmd02, cmd03, cmd10, cmd11, cmd12, cmd16, cmd17
// cmd18-1f(16进制): debug;  cmd18, cmd19, cmd1a
#define COMM_PKG_HEAD_FLAG     	0xAA
#define COMM_CMD_BASE			0x01        // communication command: first command, exchange base info
#define COMM_CMD_EXCH			0x02        // communication command: exchange data 
#define COMM_CMD_SETUP			0x03        // communication command: set m0 parameters
#define COMM_CMD_OTA_START		0x10        // communication command: start OTA
#define COMM_CMD_OTA_DATA		0x11        // communication command: transfer OTA data
#define COMM_CMD_OTA_END		0x12        // communication command: end OTA
#define COMM_CMD_SLEEP			0x16        // communication command: cat1 can sleep
#define COMM_CMD_FTM			0x17        // communication command: ftm cmd
#define COMM_CMD_DBG_LOG     	0x18        // communication command: debug cmd: print log
#define COMM_CMD_DBG_SNAP    	0x19        // communication command: debug cmd: swap io, param and st value
#define COMM_CMD_DBG_CFG    	0x1a        // communication command: debug cmd: get parameters table, include parameter name, min/max/default value

#pragma pack(1)
// 各种数据传输包头结构体, 目前用于cpu之间串口通讯, cpu和上位机的debug通讯等
typedef struct {            // debug data package head
	uint8_t flag;           // flag, = COMM_PKG_HEAD_FLAG
	uint16_t len : 11;      // 整包数据含结构体自身的长度, max. len=2048-1
	uint16_t cmd : 5;       // command, max. 32个command, 0-31
	uint8_t checksum;       // 整包数据含ZqCommPkg结构本身的校验，
	uint8_t data[0];
}ZqCommPkg;
// cmd01 resquest package
typedef struct {
	uint8_t com_protocol_ver;  			// 通讯协议版本号, 1-199, 0表示无效
	char cat1_sw_ver[ZQ_VER_MAX_LEN];	// notes: "cat1_ver" is similar "1.2.3.45", "cat1_ver_str" is similar "AAK_V1.2.3.45"
	uint8_t res[32 - ZQ_VER_MAX_LEN];	// 保留
} DtuC01RequestPkg;
// cmd01 response package
typedef struct {
	uint8_t com_protocol_ver;  			// 通讯协议版本号, 1-199, 0表示无效
    uint8_t bootmode;					// boot mode
    uint8_t ctrl_state;   				// ZyCtrlState
	uint8_t display_panel_type;			// 
	char m0_sw_ver[ZQ_VER_MAX_LEN];		// notes: "cat1_ver" is similar "1.2.3.45", "cat1_ver_str" is similar "AAK_V1.2.3.45"
	char zq_ver_prefix[8];				
	char akm_ctrl_type[4];
	char akm_dev_type[4];
	char akm_module_type[4];			 
	uint32_t akm_ctrl_func;				// bitmap functions codes
	char ble_mac[6];					// ble mac

	uint8_t res[6];
	uint8_t m0_start_cause;				// 本次M0启动原因 - 参见 START_CAUSE_M0
	uint8_t cat1_start_cause;			// 本次Cat1启动原因 - 参见 START_CAUSE_CAT1
    uint32_t m0_run_time; 				// 温控器累计运行时间(包括睡眠时间), 秒
} DtuC01ResponsePkg;
// cmd02 resquest package
typedef struct {
    uint8_t _4g;            	// 4g state: 0 - 拨号失败; 1 -- 拨号成功; 2 -- 连接上平台
    uint8_t wifi;
    uint8_t _4g_strength;   	// 4g信号强度 0-31, 99表示无效, = (RSSI + 113)/2
	uint32_t cali_time; 		// 系统校准时间, 1970年以来的秒, 0表示忽略无需校准, 和本地误差30s以上，本地校准
} DtuC02RequestPkg;
// cmd02 response package
typedef struct {
	int door1_timer;            // 门开计时s, <= 0: 门关, 由数据采样模块负责
	int door1_count;			// 门开计次, 由数据采样模块负责    
	int humman;					// 人流量计数
	short d_temp; 				// 显示温度
	short m_temp; 				// 测量温度
	short load_vol;				// 负载电压
	short load_cur;				// 负载电流
	short load_pow;				// 负载功率
	short vbat;					// 电池电压 mv, 0 - 4200, =NUM_INVALID_WORD 表示无电池
	uint8_t alarm;				// 报警
	uint8_t ctrl_mode;			// 控制器工作模式: ZqCtrlMode
	uint8_t ctrl_state;			// 控制器工作状态: ZyCtrlState
	uint8_t ctrl_switch;		// 开关状态, on/off - 1/0; b0: remote_switch, b1: hard_switch, b2: soft_switch, 所以ctrl_switch=0x07表示开关全开
	uint8_t comp_mode;			// 压机运行模式, 参见ZqCompModeEnum, 可能多个mode组合，但是当前实际按优先级运行
	uint8_t comp_state;			// 压机预计启停状态, 参见ZqCompStateEnum
	uint8_t fan_state;			// 风机工作状态
	uint8_t heater_state;		// 加热器启停状态
	uint8_t light_state;		// 灯状态

	uint16_t TS;				//设定温度; r1~r2; ℃
	uint16_t r1;				//设定温度最小值, n~TS ℃
	uint16_t r2;				//设定温度最大值, TS~n ℃
	uint16_t AH;				//高温报警值, ℃
	uint16_t AL;				//低温报警值, ℃
	uint16_t C1;				//温度上回差, .1℃
	uint16_t C2;				//温度下回差, .1℃
	uint16_t C3;				//传感器故障开机时间, M
	uint16_t C4;				//传感器故障停机时间, M
	uint16_t C5;				//显示温度补偿值, .1℃
	uint16_t C7;				//最小停机时间, M
	uint16_t d1;				//自然化霜/压机保护周期, H
	uint16_t d2;				//自然化霜/压机保护时间, M
	uint8_t res2[2];

} DtuC02ResponsePkg;

typedef struct {
    uint8_t ctrl_remote_switch; // 控制器远程开关
    uint8_t reset;          	// 控制器远程reset
    uint8_t ctrl_mode;          // 控制器模式切换
	uint8_t light_state;		// 灯控制
    short pm_TS;                // 温度设定 
    short pm_r1;                // 最小设定点	
    short pm_r2;                // 最大设定点	
    short pm_C5;                // 显示温度补偿	
    short pm_AH;                // 高温报警温度
    short pm_AL;                // 低温报警温度
} DtuC03ReqRespPkg;

#pragma pack()

// 2. 数据合法标记  --------------------------------------------------------------
#define NUM_INVALID_DWORD (0x7fffffff)							
#define NUM_INVALID_WORD (0x7fff)
#define NUM_INVALID_BYTE (0x7f)									
#define NUM_INVALID_FLOAT ((float)(-3.39e38))
#define ZQ_INVALID_PARAM (0x7fff)
#define IsByteValid(num) ((uint8_t)(num) != NUM_INVALID_BYTE)	// check if the byte/char data is valid
#define IsWordValid(num) ((uint16_t)(num) != NUM_INVALID_WORD)	// check if the word/short data is valid
#define IsDWORDValid(num) ((uint32_t)(num) != NUM_INVALID_DWORD)// check if the dword/int data is valid
#define IsFloatValid(num) ((((float)num - NUM_INVALID_FLOAT) > -0.00001) && (((float)num - NUM_INVALID_FLOAT) < 0.00001))

#define ZY_TEM_INVALID		(-1000)				//-100.0*10	// 传感器坏时候的温度
#define ZY_TEM_AUTO			(-1000)				//-100.0*10	// 自主控制温度
#define IsTemValid(num)	((short)(num) != ZY_TEM_INVALID)	// check if the dword/int data is valid


// 3. CAT1和M0共享的一些结构体 --------------------------------------------------------------

// M0启动原因
typedef enum {
    START_CAUSE_M_SW = 0,         	// 软件复位(RB_WDOG_RST_EN=0时才会产生)
    START_CAUSE_M_POWUP = 1,      	// 上电复位
    START_CAUSE_M_WDG,            	// Dog复位
    START_CAUSE_M_EXTERNAL,       	// 外部手动复位
    START_CAUSE_M_W_POWUP,        	// 唤醒复位, 且曾经是上电复位
    START_CAUSE_M_SHUTDOWN = 5,   	// 下电复位, 执行shutdown模式，被唤醒后产生
    START_CAUSE_M_W_WDG,          	// 唤醒复位, 且曾经是Dog复位
    START_CAUSE_M_W_EXTERNAL,     	// 唤醒复位, 且曾经是外部手动复位
    // 高5bit会记录app级别原因
} START_CAUSE_M0;
// Cat1启动原因
typedef enum {
    START_CAUSE_C_POWUP = 0,      	// m0上电cat1
    START_CAUSE_C_24H,        		// m0休眠24h唤醒，启动cat1执行24h上报
    START_CAUSE_C_HEARTBEAT = 1,  	// 心跳丢失复位
    START_CAUSE_C_RECONNECT10,    	// 10分钟重连重启 
    START_CAUSE_C_RECONNECT180,    	// 3*60分钟重连重启 
    START_CAUSE_C_RECONNECT1440,  	// 24*60分钟重连重启 
    START_CAUSE_C_WDG,            	// Dog复位
} START_CAUSE_CAT1;

typedef enum { // 报警状态
	ZQ_ALARM_SENSOR = 0x01,			// 温度传感器错误报警, 0 = 无报警， 1 = 报警
	ZQ_ALARM_HUMIDITY = 0x02,		// 湿度传感器错误报警, 0 = 无报警， 1 = 报警
	ZQ_ALARM_DEFROST_SENSOR = 0X02,	// 化霜传感器错误报警, 0 = 无报警， 1 = 报警 - 客人1004机型中说明：化霜传感器和湿度传感器共用错误码
	ZQ_ALARM_H = 0X04,				// 高温报警, 0 = 无报警， 1 = 报警
	ZQ_ALARM_L = 0X08,				// 低温报警, 0 = 无报警， 1 = 报警
	ZQ_ALARM_POW = 0X10,			// 断电报警, 0 = 无报警， 1 = 报警
	ZQ_ALARM_VBAT_LOW = 0X20,		// 电池电压低报警, 0 = 无报警， 1 = 报警
	ZQ_ALARM_DOOR_OPEN = 0X40,		// 门开报警, 0 = 无报警， 1 = 报警
	ZQ_ALARM_SOUND = 0x80,			// 报警音响, 0 = 不响， 1 = 响
} ZqAlarmFlag;
typedef enum { // 压机模式
	// COMP_MODE_DEFROST_END = 0x00,	// compressor defrost end
	// COMP_MODE_DELAY = 0x80,			// 压机保护模式
	// COMP_MODE_DRIP = 0x20,			// 排水模式
	COMP_MODE_FROCE = 0x20,				// 强制制冷模式
	COMP_MODE_FAULT = 0x40,				// 故障制冷模式
	COMP_MODE_NORMAL = 0x80,			// 正常运行模式
	COMP_MODE_DEFROST_MASK = 0x07,		// 化霜模式遮罩
	COMP_MODE_DEFROST_AUTO = 0x01,		// compressor defrost automatically periodly / manual defrost(not force)
	COMP_MODE_DEFROST_FORCE = 0x02,		// compressor defrost manual force
	COMP_MODE_DEFROST_PRE = 0x03,		// compressor defrost pre-forced refrigeration
	COMP_MODE_DEFROST_RUN = 0x04,		// compressor defrost runing
	COMP_MODE_DEFROST_DRAIN = 0x05,		// compressor defrost drain
	COMP_MODE_DEFROST_DRAIN2 = 0x06,	// compressor force defrost drain

}ZqCompModeEnum;
typedef enum { // 压机状态
	COMP_STATE_OFF = 0x00,		// compressor off
	COMP_STATE_RUN = 0x01,		// compressor on
	COMP_STATE_DELAY = 0x02,	// compressor delay on
}ZqCompStateEnum;
typedef enum {
	CTRL_REMOTE_SWITCH = 1,
	CTRL_HARD_SWITCH = 2,
	CTRL_SOFT_SWITCH = 4,
	CTRL_ALL_SWITCH = CTRL_REMOTE_SWITCH | CTRL_HARD_SWITCH | CTRL_SOFT_SWITCH,
}ZqCtrlSwitchEnum;

// 4. CAT1和M0共享的一些辅助宏和函数 --------------------------------------------------------------
#if ZQ_SIMULATOR  // define for simulator platform
	// format and print log
	#define _ZQ_FILE_NAME (strrchr(__FILE__, '\\')+1)
	extern const char* GetLocalTimeStrWin32(void);
//#ifdef PLATFORM_582 // windows 一旦主wpf程序启动了控制台,上子进程一般会继承主进程的console, 导致混乱
//	extern void DbgPrintf(char* fmt, ...);
//	#define ZQLOG(msg, ...) DbgPrintf("[%s] [%s:%u-%s]: "msg"\r\n",  GetLocalTimeStrWin32(), _ZQ_FILE_NAME, __LINE__, __FUNCTION__, ##__VA_ARGS__)
//#else
//	#define ZQLOG(msg, ...) printf("[%s] [%s:%u-%s]: "msg"\r\n",  GetLocalTimeStrWin32(), _ZQ_FILE_NAME, __LINE__, __FUNCTION__, ##__VA_ARGS__)
//#endif
	#define ZQLOG(msg, ...) printf("[%s] [%s:%u-%s]: "msg"\r\n",  GetLocalTimeStrWin32(), _ZQ_FILE_NAME, __LINE__, __FUNCTION__, ##__VA_ARGS__)
	// #define ZQLOG(msg, ...) printf("[%s:%u-%s]: "msg"\r\n",  _ZQ_FILE_NAME, __LINE__, __FUNCTION__, ##__VA_ARGS__)
	//#define ZQLOG(msg, ...) DbgPrintf("[%s:%u-%s]: "msg"\r\n",  _ZQ_FILE_NAME, __LINE__, __FUNCTION__, ##__VA_ARGS__)
	#define  ZQ_ALIGNED(n)	__declspec(align(n))
	#define ZQ_ASSERT(__assert, msg, ...)		do {	\
		if(!(__assert)) {								\
			for(int __ii = 0; __ii < 6000; Sleep(1000)) 		\
				if(__ii % 10 == 0) printf("ZQ:***ASSERT***:%s:%d:%s: "msg"\n",  _ZQ_FILE_NAME, __LINE__, __FUNCTION__, ##__VA_ARGS__);			\
			while(1);			\
		}												\
	} while(0);
#elif PLATFORM_582  // define for 582 platform
	extern void DbgPrintf(char* fmt, ...);
	extern void WdtClean(void);
	#define _ZQ_FILE_NAME (strrchr(__FILE__, '/')+1)
	#define ZQLOG(msg, ...) DbgPrintf("[%s:%u-%s]: "msg"\r\n",  _ZQ_FILE_NAME, __LINE__, __FUNCTION__, ##__VA_ARGS__)
	#define  ZQ_ALIGNED(n)	__attribute__((aligned(n)))
	#define ZQ_ASSERT(__assert, msg, ...)		do {	\
		if(!(__assert)) {								\
			for(int __ii = 0; __ii < 60*10; __ii++, WdtClean(), DelayMs(100)) 		\
				if(__ii % 10 == 0) ZQLOG("ZQ:***ASSERT***:%s:%d:%s: "msg"\n",  _ZQ_FILE_NAME, __LINE__, __FUNCTION__, ##__VA_ARGS__);			\
			while(1);			\
		}												\
	} while(0);
#else		// define for 8850/8910 platform
	#include "ql_log.h"
	#define _ZQ_FILE_NAME (strrchr(__FILE__, '/')+1)
	#define ZQLOG(msg, ...) printf("ZQ:%s:%d:%s: "msg"\n",  _ZQ_FILE_NAME, __LINE__, __FUNCTION__, ##__VA_ARGS__)
	// 致命错误，无法恢复，1000秒倒计时重启, 
	#define ZQ_ASSERT(__assert, msg, ...)		do {	\
		if(!(__assert)) {								\
			for(int __ii = 0; __ii < 1000; __ii++, ql_rtos_task_sleep_s(1)) 		\
				printf("ZQ:***ASSERT***:%s:%d:%s: "msg"\n",  _ZQ_FILE_NAME, __LINE__, __FUNCTION__, ##__VA_ARGS__);			\
			ql_power_reset(RESET_NORMAL);			\
		}												\
	} while(0);
#endif


// swap endianess
#define ZQ_SWAP_WORD(word) ((uint16_t)(((uint16_t)(word) << 8) | ((uint16_t)(word) >> 8)))
#define ZQ_SWAP_DWORD(dword) (uint32_t)(((uint32_t)(ZQ_SWAP_WORD((dword) >> 16)) | ((uint32_t)ZQ_SWAP_WORD((dword)) << 16)))

extern void ZqHexDump(const char *head, unsigned char* data, unsigned int len);
extern uint8_t ZqGetChecksum(uint8_t* data, unsigned int len);
extern uint8_t GetVbatPercentage(short vbat);


// general fifo buffer fuctions -----------------------------------------------------------------------------------------------
typedef struct {
    void (*lock)(uint8_t locked); 	// 提供锁定函数，参数locked = 1上锁， =0解锁
    uint16_t max_size;
    uint16_t len;
    uint8_t data[0];
} ZqFifoBuf;

// create the linear buffer, max len < 32k
extern ZqFifoBuf *ZqFifoBufCreate(uint16_t size, void (*lock)(uint8_t locked));
// flush the len-length data from the 0-offset, and copy the left data to the begin of the buffer
extern uint16_t ZqFifoBufFlush(ZqFifoBuf *buf, uint16_t len);
// write data to buf
extern uint16_t ZqFifoBufWrite(ZqFifoBuf *buf, uint8_t *data, uint16_t len);

// covert date to second from 1970, 参考网上unix标准算法.
extern uint32_t ZqDateToTimestamp(uint16_t year, uint16_t mon, uint16_t day, uint16_t hour, uint16_t min, uint16_t sec);
// covert second from 1970 to date, 参考网上unix标准算法. note: begin from 2024-01-01 00:00:00
extern void ZqTimestampToDate(uint32_t timestamp, uint16_t *year, uint16_t *mon, uint16_t *day, uint16_t *hour, uint16_t *min, uint16_t *sec);

//// general Circle buffer fuctions -----------------------------------------------------------------------------------------------
//typedef struct {
//	uint16_t r_pos;
//	uint16_t data_len;
//	void (*lock)(uint8_t locked); 	// 提供锁定函数，参数locked = 1上锁， =0解锁
//	uint8_t overflow;				// overflow flag
//	uint8_t reserve;
//	uint16_t buf_size;
//	uint8_t buf[0];
//} ZqCircleBuf;
//
//// create the linear buffer, max len < 32k
//extern ZqCircleBuf* ZqCircleBufCreate(uint16_t size, void (*lock)(uint8_t locked));
//extern uint8_t ZqCircleBufIsOverflow(ZqCircleBuf* l_buf);
//extern uint16_t ZqCircleBufGetDataLen(ZqCircleBuf* l_buf);
//// discard len of data, return left data length
//extern uint16_t ZqCircleBufDiscard(ZqCircleBuf* l_buf, uint16_t len);
//// directly get data buf and data len in the l_buf stream, use can use the data without copyout, once using done, call discard fucntion to realese data
//extern uint8_t* ZqCircleBufGetBuf(ZqCircleBuf* l_buf, uint16_t* plen);
//extern uint16_t ZqCircleBufRead(ZqCircleBuf* l_buf, uint8_t* buf, uint16_t len);
//extern uint16_t ZqCircleBufWrite(ZqCircleBuf* l_buf, uint8_t* data, uint16_t len);
